package com.shiguiwu.springmybatis.spring.aop.principle.factory;

import com.shiguiwu.springmybatis.spring.aop.principle.MyAdvisedSupport;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.cglib.proxy.Proxy;

/**
 * @description: 默认实现
 * @author: stone
 * @date: Created by 2021/6/4 14:01
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.aop.principle.factory
 */
public class MyDefaultAopProxyFactory implements MyAopProxyFactory {



    /**
     * 默认AopProxyFactory实现，创建CGLIB代理或JDK动态代理。
     * 对于给定的AdvisedSupport实例，以下条件为真，则创建一个CGLIB代理:
     * optimize = true
     * proxyTargetClass = true
     * 未指定代理接口
     代理创建阶段
     到目前为止我们已经根据aop配置信息得到了AopProxy对象了，下面就可以调用AopProxy.getProxy方
     法获取代理对象了。
     AopProxy.createAopProxy方法返回的结果有2种情况
     JdkDynamicAopProxy：以jdk动态代理的方式创建代理
     ObjenesisCglibAopProxy：以cglib的方式创建动态代理
     项目详解这2个类的源码 。
     * 通常，指定proxyTargetClass来强制执行CGLIB代理，或者指定一个或多个接口来使用JDK动态代理。
     */
    @Override
    public Object createAopProxy(MyAdvisedSupport config) {
        if (config.isOptimize() || config.isProxyTargetClass() || this.hasNoUserSuppliedProxyInterfaces(config)) {
             //获取需要被代理的类
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            }
            //如果被代理的类为接口 或者 被代理的类是jdk动态代理创建代理类，则采用
//            JdkDynamicAopProxy的方式，否则采用cglib代理的方式
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {//采用jdk动态代理的方式
                return null;
            }
            //采用cglib代理的方式
            return null;
        }
        else {
            return null;

        }
    }


    /**
     * 确定所提供的AdvisedSupport是否只指定了SpringProxy接口(或者根本没有指定代理接口)
     */
    private boolean hasNoUserSuppliedProxyInterfaces(MyAdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 &&
                SpringProxy.class.isAssignableFrom(ifcs[0])));
    }
}
